package com.bougaga.opensource.scheduler.core.task;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.io.Serializable;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;

/**
 * 延迟任务定义
 * 
 * @author bougaga
 * @since 1.0.0
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class DelayedTask implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    /**
     * 任务ID
     */
    private String taskId;
    
    /**
     * 任务名称
     */
    private String taskName;
    
    /**
     * 任务类型
     */
    private String taskType;
    
    /**
     * 任务数据（JSON格式）
     */
    private String taskData;
    
    /**
     * 执行时间
     */
    private LocalDateTime executeTime;
    
    /**
     * 延迟时间（毫秒）
     */
    private Long delayMillis;
    
    /**
     * 任务状态
     */
    private TaskStatus status;
    
    /**
     * 重试次数
     */
    private Integer retryCount;
    
    /**
     * 最大重试次数
     */
    private Integer maxRetryCount;
    
    /**
     * 重试间隔（毫秒）
     */
    private Long retryInterval;
    
    /**
     * 创建时间
     */
    private LocalDateTime createTime;
    
    /**
     * 更新时间
     */
    private LocalDateTime updateTime;
    
    /**
     * 扩展属性
     */
    private Map<String, Object> properties;
    
    /**
     * 任务处理器名称
     */
    private String handlerName;
    
    /**
     * 优先级（数字越小优先级越高）
     */
    private Integer priority;
    
    /**
     * 是否持久化
     */
    private Boolean persistent;
    
    public DelayedTask() {
        this.taskId = UUID.randomUUID().toString();
        this.createTime = LocalDateTime.now();
        this.updateTime = LocalDateTime.now();
        this.status = TaskStatus.PENDING;
        this.retryCount = 0;
        this.maxRetryCount = 3;
        this.retryInterval = 5000L;
        this.priority = 0;
        this.persistent = true;
    }
    
    public DelayedTask(String taskName, String taskType, String taskData, LocalDateTime executeTime) {
        this();
        this.taskName = taskName;
        this.taskType = taskType;
        this.taskData = taskData;
        this.executeTime = executeTime;
    }
    
    public DelayedTask(String taskName, String taskType, String taskData, Long delayMillis) {
        this();
        this.taskName = taskName;
        this.taskType = taskType;
        this.taskData = taskData;
        this.delayMillis = delayMillis;
        this.executeTime = LocalDateTime.now().plusNanos(delayMillis * 1_000_000);
    }
    
    // Getters and Setters
    public String getTaskId() {
        return taskId;
    }
    
    public void setTaskId(String taskId) {
        this.taskId = taskId;
    }
    
    public String getTaskName() {
        return taskName;
    }
    
    public void setTaskName(String taskName) {
        this.taskName = taskName;
    }
    
    public String getTaskType() {
        return taskType;
    }
    
    public void setTaskType(String taskType) {
        this.taskType = taskType;
    }
    
    public String getTaskData() {
        return taskData;
    }
    
    public void setTaskData(String taskData) {
        this.taskData = taskData;
    }
    
    public LocalDateTime getExecuteTime() {
        return executeTime;
    }
    
    public void setExecuteTime(LocalDateTime executeTime) {
        this.executeTime = executeTime;
    }
    
    public Long getDelayMillis() {
        return delayMillis;
    }
    
    public void setDelayMillis(Long delayMillis) {
        this.delayMillis = delayMillis;
    }
    
    public TaskStatus getStatus() {
        return status;
    }
    
    public void setStatus(TaskStatus status) {
        this.status = status;
        this.updateTime = LocalDateTime.now();
    }
    
    public Integer getRetryCount() {
        return retryCount;
    }
    
    public void setRetryCount(Integer retryCount) {
        this.retryCount = retryCount;
    }
    
    public Integer getMaxRetryCount() {
        return maxRetryCount;
    }
    
    public void setMaxRetryCount(Integer maxRetryCount) {
        this.maxRetryCount = maxRetryCount;
    }
    
    public Long getRetryInterval() {
        return retryInterval;
    }
    
    public void setRetryInterval(Long retryInterval) {
        this.retryInterval = retryInterval;
    }
    
    public LocalDateTime getCreateTime() {
        return createTime;
    }
    
    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }
    
    public LocalDateTime getUpdateTime() {
        return updateTime;
    }
    
    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }
    
    public Map<String, Object> getProperties() {
        return properties;
    }
    
    public void setProperties(Map<String, Object> properties) {
        this.properties = properties;
    }
    
    public String getHandlerName() {
        return handlerName;
    }
    
    public void setHandlerName(String handlerName) {
        this.handlerName = handlerName;
    }
    
    public Integer getPriority() {
        return priority;
    }
    
    public void setPriority(Integer priority) {
        this.priority = priority;
    }
    
    public Boolean getPersistent() {
        return persistent;
    }
    
    public void setPersistent(Boolean persistent) {
        this.persistent = persistent;
    }
    
    /**
     * 获取任务延迟时间（毫秒）
     */
    @JsonIgnore
    public long getDelayTimeMillis() {
        if (executeTime == null) {
            return 0;
        }
        long delay = Duration.between(LocalDateTime.now(), executeTime).toMillis();
        return Math.max(0, delay);
    }
    
    /**
     * 是否可以重试
     */
    @JsonIgnore
    public boolean canRetry() {
        return retryCount < maxRetryCount;
    }
    
    /**
     * 增加重试次数
     */
    public void incrementRetryCount() {
        this.retryCount++;
        this.updateTime = LocalDateTime.now();
    }
    
    /**
     * 重置重试次数
     */
    public void resetRetryCount() {
        this.retryCount = 0;
        this.updateTime = LocalDateTime.now();
    }
    
    @Override
    public String toString() {
        return "DelayedTask{" +
                "taskId='" + taskId + '\'' +
                ", taskName='" + taskName + '\'' +
                ", taskType='" + taskType + '\'' +
                ", executeTime=" + executeTime +
                ", status=" + status +
                ", retryCount=" + retryCount +
                '}';
    }
}
